package org.dfl.core.utils;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

import org.apache.log4j.Logger;

/**
 * class to manage jars
 * @author Piotr Wlodarczyk
 *
 */
public class JarUtils {
	private static Logger logger = Logger.getLogger(JarUtils.class);
	
	public static Set<String> getPackagesList(String[] jarNames) {
		Set<String> res = new HashSet<String>();
		
		if(jarNames != null)
		for(String jarName : jarNames){
			try {
				JarInputStream jarFile = new JarInputStream(new FileInputStream(jarName));
				JarEntry jarEntry;
	
				while (true) {
					jarEntry = jarFile.getNextJarEntry();
					if (jarEntry == null) {
						break;
					}
					if (jarEntry.getName().endsWith(".class")) {
						String name = jarEntry.getName().replaceAll("/", "\\.");
						name = name.substring(0,name.length()-6); // delete .class
						res.add(getPackageNameFromClassStr(name));
					}
				}
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
		}
		
		return res;
	}
	
	public static List<String> getClasseNamesInPackage(String[] jarNames, String packageName) {
		ArrayList<String> classes = new ArrayList<String>();
		if(jarNames== null || packageName ==null){
			return classes;
		}
		packageName = packageName.replaceAll("\\.", "/");
		
		if(jarNames!=null)
		for(String jarName : jarNames){
			try {
				JarInputStream jarFile = new JarInputStream(new FileInputStream(jarName));
				JarEntry jarEntry;
	
				while (true) {
					jarEntry = jarFile.getNextJarEntry();
					if (jarEntry == null) {
						break;
					}
					if ((jarEntry.getName().startsWith(packageName))
							&& (jarEntry.getName().endsWith(".class"))) {
						String name = jarEntry.getName().replaceAll("/", "\\.");
						name = name.substring(0,name.length()-6); // delete .class
						classes.add(getClassNameFromClassStr(name));
					}
				}
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
		}
		return classes;
	}
	
	public static String getClassNameFromClassStr(String classStr){
		return classStr.replaceAll(".*\\.", "");
	}
	
	public static String getPackageNameFromClassStr(String classStr){
		return classStr.substring(0,classStr.length()-getClassNameFromClassStr(classStr).length()-1);
	}
	
	public static URLClassLoader getClassLoader(String[] jarList) throws MalformedURLException {
		URL[] urls = new URL[jarList.length];
		for(int i=0; i<jarList.length; i++){
			urls[i] = new File(jarList[i]).toURL();
		}
		return new URLClassLoader(urls);
	}
	
	@SuppressWarnings("unchecked")
	public static List<Method> getClassMethods(Class c){
		List<Method> res = new ArrayList<Method>();
		if(c!=null){
			Method[] methods = c.getMethods();
			for(Method m : methods){
				res.add(m);
			}
		}
		return res;
	}
	
	@SuppressWarnings("unchecked")
	public static List<Method> getClassStaticMethods(Class c){
		List<Method> methods = getClassMethods(c);
		List<Method> res = new ArrayList<Method>();
		for(Method m : methods){
			if(Modifier.isStatic(m.getModifiers())){
				res.add(m);
			}
		}
		return res;
	}	
}
